{{!

  Copyright (c) Facebook, Inc. and its affiliates.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

}}{{!

Wraps structs and exceptions defined in the thrift interface file and implemented
in the cpp2 generated code. This file just exposes the C++ classes and attributes
to Cython. The Pythonic wrappers of the individual structs and fields are
implemented in the Struct.pyx file.

}}
{{> common/AutoGeneratedPy}}

from libc.stdint cimport (
    int8_t as cint8_t,
    int16_t as cint16_t,
    int32_t as cint32_t,
    int64_t as cint64_t,
    uint32_t as cuint32_t,
)
from libcpp.string cimport string
from libcpp cimport bool as cbool, nullptr, nullptr_t
from cpython cimport bool as pbool
from libcpp.memory cimport shared_ptr, unique_ptr
from libcpp.vector cimport vector
from libcpp.set cimport set as cset
from libcpp.map cimport map as cmap, pair as cpair
from thrift.py3.exceptions cimport cTException
cimport folly.iobuf as __iobuf
cimport thrift.py3.exceptions
cimport thrift.py3.types
from thrift.py3.types cimport bstring, move, optional_field_ref
from folly.optional cimport cOptional
{{#program:has_stream?}}
from folly cimport cFollyTry
from cpython.ref cimport PyObject
from thrift.py3.stream cimport (
    ClientBufferedStream, cClientBufferedStream, cClientBufferedStreamWrapper,
    ResponseAndClientBufferedStream, cResponseAndClientBufferedStream,
    ServerStream, cServerStream, ResponseAndServerStream
)
from thrift.py3.common cimport RpcOptions as __RpcOptions
{{/program:has_stream?}}
{{#program:includeNamespaces}}
cimport {{#includeNamespace}}{{value}}.{{/includeNamespace}}types as _{{#includeNamespace}}{{value}}_{{/includeNamespace}}types
{{/program:includeNamespaces}}

{{#program:cppIncludes}}
cdef extern from "{{.}}":
  pass
{{/program:cppIncludes}}{{!
}}{{#program:customTemplates}}
{{> CustomTemplate}}
{{/program:customTemplates}}{{!
}}{{#program:customTypes}}
{{> CustomType}}
{{/program:customTypes}}

{{#program:enums}}
{{#first?}}
cdef extern from "{{program:includePrefix}}gen-cpp2/{{program:name}}_types.h"{{!
}} namespace "{{#program:cppNamespaces}}::{{value}}{{/program:cppNamespaces}}":
{{/first?}}
    cdef cppclass c{{enum:name}} "::{{#program:cppNamespaces}}{{value}}::{{/program:cppNamespaces}}{{enum:name}}":
        bint operator==(c{{enum:name}}&)
        bint operator!=(c{{enum:name}}&)
    {{#enum:values}}
    c{{enum:name}} {{enum:name}}__{{enumValue:py_name}} "::{{#program:cppNamespaces}}{{value}}::{{/program:cppNamespaces}}{{enum:name}}::{{enumValue:cppName}}"
    {{/enum:values}}
{{/program:enums}}


{{> types/enumDefs }}

{{#program:structs}}
{{#first?}}
cdef extern from "{{program:includePrefix}}gen-cpp2/{{program:name}}_types_custom_protocol.h"{{!
}} namespace "{{#program:cppNamespaces}}::{{value}}{{/program:cppNamespaces}}":
{{/first?}}
    # Forward Declaration
    cdef cppclass c{{struct:name}} "::{{#program:cppNamespaces}}{{value}}::{{/program:cppNamespaces}}{{struct:name}}"{{#struct:exception?}}(cTException){{/struct:exception?}}
{{/program:structs}}

{{#program:structs}}
{{#first?}}
cdef extern from "{{program:includePrefix}}gen-cpp2/{{program:name}}_types.h"{{!
}} namespace "{{#program:cppNamespaces}}::{{value}}{{/program:cppNamespaces}}":
{{/first?}}
    {{^struct:union?}}
    cdef cppclass c{{struct:name}}__isset "::{{#program:cppNamespaces}}{{value}}::{{/program:cppNamespaces}}{{struct:name}}::__isset":
    {{#struct:fields}}
        bint {{field:py_name}}{{#field:hasModifiedName?}} "{{field:cppName}}"{{/field:hasModifiedName?}}
    {{/struct:fields}}
    {{^struct:fields}}
        pass
    {{/struct:fields}}
    {{/struct:union?}}
    {{#struct:union?}}
    cdef enum c{{struct:name}}__type "::{{#program:cppNamespaces}}{{value}}::{{/program:cppNamespaces}}{{struct:name}}::Type":
        c{{struct:name}}__type___EMPTY__ "::{{#program:cppNamespaces}}{{value}}::{{/program:cppNamespaces}}{{struct:name}}::Type::__EMPTY__",
    {{#struct:fields}}
        c{{struct:name}}__type_{{field:py_name}} "::{{#program:cppNamespaces}}{{value}}::{{/program:cppNamespaces}}{{struct:name}}::Type::{{field:cppName}}",
    {{/struct:fields}}
    {{/struct:union?}}

    cdef cppclass c{{struct:name}} "::{{#program:cppNamespaces}}{{value}}::{{/program:cppNamespaces}}{{struct:name}}"{{#struct:exception?}}(cTException){{/struct:exception?}}:
        c{{struct:name}}() except +
        c{{struct:name}}(const c{{struct:name}}&) except +
        {{^struct:cpp_noncomparable}}
        bint operator==(c{{struct:name}}&)
        bint operator!=(c{{struct:name}}&)
        {{#struct:is_struct_orderable?}}
        bint operator<(c{{struct:name}}&)
        bint operator>(c{{struct:name}}&)
        bint operator<=(c{{struct:name}}&)
        bint operator>=(c{{struct:name}}&)
        {{/struct:is_struct_orderable?}}
        {{/struct:cpp_noncomparable}}
    {{^struct:union?}}
    {{#struct:fields}}
        {{#field:has_ref_accessor?}}
        optional_field_ref[{{#field:type}}{{> types/CythonCppStructFieldType}}{{/field:type}}] {{!
            }}{{field:py_name}}_ref{{#field:hasModifiedName?}} "{{field:cppName}}_ref"{{/field:hasModifiedName?}}()
        {{/field:has_ref_accessor?}}
        {{^field:has_ref_accessor?}}
        {{#field:type}}{{> types/CythonCppStructFieldType}}{{/field:type}} {{field:py_name}}{{#field:hasModifiedName?}} "{{field:cppName}}"{{/field:hasModifiedName?}}
        {{/field:has_ref_accessor?}}
    {{/struct:fields}}
        c{{struct:name}}__isset __isset
    {{/struct:union?}}
    {{#struct:union?}}
        c{{struct:name}}__type getType() const
    {{#struct:fields}}
        {{#field:type}}const {{> types/CythonCppStructFieldType}}& get_{{field:py_name}}{{#field:hasModifiedName?}} "get_{{field:cppName}}"{{/field:hasModifiedName?}}() const{{/field:type}}
        {{! Note that the set methods don't take in a shared/unique_ptr, they just take in an object ref,
            but they return the appropriate ptr }}
        {{#field:type}}{{> types/CythonCppStructFieldType}}& set_{{field:py_name}}{{#field:hasModifiedName?}} "set_{{field:cppName}}"{{/field:hasModifiedName?}}(const {{> types/CythonCppType}}&){{/field:type}}
    {{/struct:fields}}{{/struct:union?}}

{{/program:structs}}{{!

}}{{#program:structs}}{{#struct:fields}}{{#field:reference?}}{{^field:iobuf_ref?}}{{#field:type}}
    cdef shared_ptr[{{> types/CythonCppType}}] {{!
    }}reference_shared_ptr_{{field:py_name}} {{!
    }}"thrift::py3::reference_shared_ptr<{{> types/CppValueType}}>"({{!
    }}shared_ptr[c{{struct:name}}]&, {{> types/CythonCppType}}&)
{{/field:type}}{{/field:iobuf_ref?}}{{/field:reference?}}
{{^field:reference?}}{{#field:type}}{{^type:simple?}}
    cdef shared_ptr[{{> types/CythonCppType}}] {{!
    }}reference_shared_ptr_{{field:py_name}} {{!
    }}"thrift::py3::reference_shared_ptr<{{> types/CppValueType}}>"({{!
    }}shared_ptr[c{{struct:name}}]&, {{> types/CythonCppType}}&)
{{/type:simple?}}{{/field:type}}{{/field:reference?}}
{{/struct:fields}}{{/program:structs}}

{{#program:structs}}
{{#first?}}cdef extern from "<utility>" namespace "std" nogil:{{/first?}}
    cdef shared_ptr[c{{struct:name}}] move(unique_ptr[c{{struct:name}}])
    cdef shared_ptr[c{{struct:name}}] move_shared "std::move"(shared_ptr[c{{struct:name}}])
    cdef unique_ptr[c{{struct:name}}] move_unique "std::move"(unique_ptr[c{{struct:name}}]){{/program:structs}}

{{#program:structs}}
{{#first?}}cdef extern from "<memory>" namespace "std" nogil:{{/first?}}
    cdef shared_ptr[const c{{struct:name}}] const_pointer_cast {{!
    }}"std::const_pointer_cast<const {{!
    }}::{{#program:cppNamespaces}}{{value}}::{{/program:cppNamespaces}}{{struct:name}}{{!
    }}>"(shared_ptr[c{{struct:name}}]){{/program:structs}}

{{#program:structs}}
{{#struct:union?}}
cdef class __{{struct:name}}Type(thrift.py3.types.CompiledEnum):
    pass


{{/struct:union?}}
# Forward Definition of the cython struct
cdef class {{struct:name}}({{> types/PythonStructClass}})


cdef class {{struct:name}}({{> types/PythonStructClass}}):
    cdef object __hash
    cdef object __weakref__
    cdef shared_ptr[c{{struct:name}}] _cpp_obj
    {{^struct:union?}}
    {{!Memoized Python wrappers of struct fields, created lazily}}
    {{#struct:fields}}
    {{#field:type}}{{#type:struct}}
    cdef {{> types/CythonPythonType}} __field_{{field:py_name}}
    {{/type:struct}}{{#type:container?}}
    cdef {{> types/CythonPythonType}} __field_{{field:py_name}}
    {{/type:container?}}{{#type:iobuf?}}
    cdef __iobuf.IOBuf __field_{{field:py_name}}
    {{/type:iobuf?}}{{#type:iobufRef?}}
    cdef __iobuf.IOBuf __field_{{field:py_name}}
    {{/type:iobufRef?}}{{/field:type}}
    {{/struct:fields}}{{/struct:union?}}
    {{#struct:union?}}
    cdef readonly __{{struct:name}}Type type
    cdef readonly object value
    cdef _load_cache({{struct:name}} self)
    {{/struct:union?}}
    {{#struct:cpp_noncomparable}}
    cdef __{{struct:name}}_eq({{struct:name}} self, {{struct:name}} other)
    {{/struct:cpp_noncomparable}}

    @staticmethod
    cdef unique_ptr[c{{struct:name}}] _make_instance(
        c{{struct:name}}* base_instance{{^struct:union?}},
        bint* __isNOTSET{{/struct:union?}}{{#struct:fields}},
        {{#field:type}}{{!
            }}{{#type:cythonTypeNoneable?}}{{!
                }}{{> types/CythonPythonType}} {{!
            }}{{/type:cythonTypeNoneable?}}{{!
            }}{{^type:cythonTypeNoneable?}}{{!
                }}object {{!
            }}{{/type:cythonTypeNoneable?}}{{!
            }}{{field:py_name}}{{!
        }}{{/field:type}}{{/struct:fields}}
    ) except *

    @staticmethod
    cdef create(shared_ptr[c{{struct:name}}])

{{/program:structs}}

{{#program:containerTypes}}
cdef class {{> types/CythonPythonType}}(thrift.py3.types.Container):
    cdef shared_ptr[{{> types/CythonCppType}}] _cpp_obj
    @staticmethod
    cdef create(shared_ptr[{{> types/CythonCppType}}])
    @staticmethod
    cdef shared_ptr[{{> types/CythonCppType}}] _make_instance(object items) except *

{{/program:containerTypes}}{{#program:moveContainerTypes}}
{{#first?}}cdef extern from "<utility>" namespace "std" nogil:{{/first?}}
    cdef shared_ptr[{{> types/CythonCppType}}] move "std::move"(unique_ptr[{{> types/CythonCppType}}])
    cdef shared_ptr[{{> types/CythonCppType}}] move_shared "std::move"(shared_ptr[{{> types/CythonCppType}}]){{!
}}{{/program:moveContainerTypes}}
{{#program:containerTypes}}
{{#first?}}
cdef extern from "<utility>" nogil:
    pass  {{! incase we have no containers in containers }}
{{/first?}}
{{#type:list?}}
{{#type:listElemType}}
{{^type:simple?}}
    shared_ptr[{{> types/CythonCppType}}] reference_shared_ptr_{{containerType:flat_name}} {{!
    }}"thrift::py3::reference_shared_ptr<{{> types/CppValueType}}>"(...)
{{/type:simple?}}
{{/type:listElemType}}
{{/type:list?}}
{{#type:set?}}
{{#type:setElemType}}
{{^type:simple?}}
    shared_ptr[{{> types/CythonCppType}}] reference_shared_ptr_{{containerType:flat_name}} {{!
    }}"thrift::py3::reference_shared_ptr<{{> types/CppValueType}}>"(...)
{{/type:simple?}}
{{/type:setElemType}}
{{/type:set?}}
{{#type:map?}}
{{#type:keyType}}
{{^type:simple?}}
    shared_ptr[{{> types/CythonCppType}}] reference_shared_ptr_{{containerType:flat_name}}_key {{!
    }}"thrift::py3::reference_shared_ptr<{{> types/CppValueType}}>"(...)
{{/type:simple?}}
{{/type:keyType}}
{{#type:valueType}}
{{^type:simple?}}
    shared_ptr[{{> types/CythonCppType}}] reference_shared_ptr_{{containerType:flat_name}} {{!
    }}"thrift::py3::reference_shared_ptr<{{> types/CppValueType}}>"(...)
{{/type:simple?}}
{{/type:valueType}}
{{/type:map?}}{{!
}}{{/program:containerTypes}}{{!

}}{{#program:moveContainerTypes}}
{{#first?}}
cdef extern from "<memory>" namespace "std" nogil:{{/first?}}
    cdef shared_ptr[const {{> types/CythonCppType}}] const_pointer_cast {{!
    }}"std::const_pointer_cast<const {{> types/CppValueType}}>"{{!
    }}(shared_ptr[{{> types/CythonCppType}}]){{/program:moveContainerTypes}}

{{#program:constants}}
{{#first?}}
cdef extern from "{{program:includePrefix}}gen-cpp2/{{program:name}}_constants.h"{{!
}} namespace "{{#program:cppNamespaces}}::{{value}}{{/program:cppNamespaces}}":
{{/first?}}
    {{#constant:type}}
    cdef {{^type:string?}}{{> types/CythonCppType}}{{/type:string?}}{{#type:string?}}const char*{{/type:string?}} {{!
    }}c{{constant:name}} "::{{#program:cppNamespaces}}{{value}}::{{/program:cppNamespaces}}{{program:name}}_constants::{{constant:name}}"{{!
    }}{{#type:struct?}}(){{/type:struct?}}{{#type:string?}}(){{/type:string?}}{{#type:binary?}}(){{/type:binary?}}{{#type:container?}}(){{/type:container?}}{{#type:enum?}}(){{/type:enum?}}
{{/constant:type}}{{/program:constants}}
{{#program:has_stream?}}{{! check if it's a stream case and if not short-circuit it to save get stream_types calls }}

{{#program:stream_types}}
{{#first?}}cdef extern from "<utility>" namespace "std" nogil:{{/first?}}
    cdef cClientBufferedStream[{{ > types/CythonCppType}}] move_semistream "std::move"(cClientBufferedStream[{{ > types/CythonCppType}}])
{{/program:stream_types}}

{{#program:stream_types}}
cdef class ClientBufferedStream__{{type:flat_name}}(ClientBufferedStream):
    cdef unique_ptr[cClientBufferedStreamWrapper[{{ > types/CythonCppType}}]] _gen

    @staticmethod
    cdef create(cClientBufferedStream[{{ > types/CythonCppType}}]& c_obj, __RpcOptions rpc_options)

    @staticmethod
    cdef void callback(
        cFollyTry[cOptional[{{ > types/CythonCppType}}]]&& res,
        PyObject* userdata,
    )

cdef class ServerStream__{{type:flat_name}}(ServerStream):
    pass

{{/program:stream_types}}
{{#program:response_and_stream_types}}

cdef class ResponseAndClientBufferedStream__{{> stream/ResponseClassNameSuffix}}(ResponseAndClientBufferedStream):
    cdef ClientBufferedStream__{{#type:streamElemType}}{{type:flat_name}}{{/type:streamElemType}} _stream
    cdef {{#type:streamFirstResponseType}}{{ > types/CythonPythonType}}{{/type:streamFirstResponseType}} _response

    @staticmethod
    cdef create(cResponseAndClientBufferedStream[{{!
        }}{{#type:streamFirstResponseType}}{{ > types/CythonCppType}}{{/type:streamFirstResponseType}}, {{!
        }}{{#type:streamElemType}}{{ > types/CythonCppType}}{{/type:streamElemType}}]& c_obj, __RpcOptions rpc_options)


cdef class ResponseAndServerStream__{{> stream/ResponseClassNameSuffix}}(ResponseAndServerStream):
    pass

{{/program:response_and_stream_types}}
{{/program:has_stream?}}
